/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.rbac.service.permission.template.impl;

import com.google.common.base.Strings;
import com.je.common.base.DynaBean;
import com.je.common.base.expression.SpringElPermissionParserContext;
import com.je.common.base.service.CommonService;
import com.je.common.base.service.MetaService;
import com.je.ibatis.extension.conditions.ConditionsWrapper;
import com.je.rbac.service.permission.PermissionOperationTypeEnum;
import com.je.rbac.service.permission.PermissionTypeEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.ParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

public abstract class AbstractPermissionTemplateService {

    /**
     * 表达式解析器
     */
    private static final ExpressionParser PARSER = new SpelExpressionParser();
    private static final ParserContext PARSER_CONTEXT = new SpringElPermissionParserContext();

    @Autowired
    private CommonService commonService;

    @Autowired
    protected MetaService metaService;

    protected void removeFuncPermission(String permCode) {
        metaService.delete("JE_RBAC_PERM", ConditionsWrapper.builder().eq("PERM_CODE", permCode));
    }

    protected void removeRoleFuncPermission(String roleId, String permCode, boolean cascade) {
        DynaBean permBean = metaService.selectOne("JE_RBAC_PERM",ConditionsWrapper.builder().eq("PERM_CODE",permCode));
        if(permBean == null){
            return;
        }
        metaService.delete("JE_RBAC_ROLEPERM",ConditionsWrapper.builder()
                .eq("JE_RBAC_ROLE_ID",roleId)
                .eq("JE_RBAC_PERM_ID",permBean.getStr("JE_RBAC_PERM_ID")));
        if(cascade){
            metaService.delete("JE_RBAC_PERM", ConditionsWrapper.builder().eq("JE_RBAC_PERM_ID", permBean.getStr("JE_RBAC_PERM_ID")));
        }
    }

    protected void removeDeptFuncPermission(String deptId, String permCode, boolean cascade) {
        DynaBean permBean = metaService.selectOne("JE_RBAC_PERM",ConditionsWrapper.builder().eq("PERM_CODE",permCode));
        if(permBean == null){
            return;
        }
        metaService.delete("JE_RBAC_DEPTPERM",ConditionsWrapper.builder()
                .eq("JE_RBAC_DEPARTMENT_ID",deptId)
                .eq("JE_RBAC_PERM_ID",permBean.getStr("JE_RBAC_PERM_ID")));
        if(cascade){
            metaService.delete("JE_RBAC_PERM", ConditionsWrapper.builder().eq("JE_RBAC_PERM_ID", permBean.getStr("JE_RBAC_PERM_ID")));
        }
    }

    protected void removeOrgFuncPermission(String orgId, String permCode, boolean cascade) {
        DynaBean permBean = metaService.selectOne("JE_RBAC_PERM",ConditionsWrapper.builder().eq("PERM_CODE",permCode));
        if(permBean == null){
            return;
        }
        metaService.delete("JE_RBAC_ORGPERM",ConditionsWrapper.builder()
                .eq("JE_RBAC_ORG_ID",orgId)
                .eq("JE_RBAC_PERM_ID",permBean.getStr("JE_RBAC_PERM_ID")));
        if(cascade) {
            metaService.delete("JE_RBAC_PERM", ConditionsWrapper.builder().eq("JE_RBAC_PERM_ID", permBean.getStr("JE_RBAC_PERM_ID")));
        }
    }

    /**
     * 保存非输出型权限
     *
     * @param permissionTypeEnum
     * @param name
     * @param code
     * @param object
     * @param operationType
     * @return
     */
    protected DynaBean writePcFuncPermissionWithoutOutput(PermissionTypeEnum permissionTypeEnum, String name, String code,
                                                          String object, PermissionOperationTypeEnum operationType) {
        DynaBean permissionBean = new DynaBean("JE_RBAC_PERM", false);
        permissionBean.set("PERM_NAME", name);
        permissionBean.set("PERM_CODE", code);
        permissionBean.set("PERM_OUTPUT_CODE", "0");
        permissionBean.set("PERM_OUTPUT_NAME", "否");
        permissionBean.set("PERM_OUTPUT_TEMPLATE", "");
        //todo 设置租户
        permissionBean.set("SY_TENANT_ID", "");
        permissionBean.set("SY_TENANT_NAME", "");
        permissionBean.set("PERM_EXCLUDE_CODE", "0");
        permissionBean.set("PERM_EXCLUDE_NAME", "否");
        permissionBean.set("PERM_TYPE_CODE", permissionTypeEnum.name());
        permissionBean.set("PERM_TYPE_NAME", permissionTypeEnum.getDesc());
        permissionBean.set("PERM_OBJECT", object);
        permissionBean.set("PERM_OPERATE_CODE", operationType.getCode());
        permissionBean.set("PERM_OPERATE_NAME", operationType.getDesc());
        commonService.buildModelCreateInfo(permissionBean);
        metaService.insert(permissionBean);
        return permissionBean;
    }

    //---------------------------功能数据---------------------------

    protected DynaBean writeDataPermission(PermissionTypeEnum typeEnum, String name, String code, String object, boolean output, String outputTemplate, PermissionOperationTypeEnum operationType) {
        DynaBean permissionBean = new DynaBean("JE_RBAC_PERM", false);
        permissionBean.set("PERM_NAME", name);
        permissionBean.set("PERM_CODE", code);
        if (output) {
            permissionBean.set("PERM_OUTPUT_CODE", "1");
            permissionBean.set("PERM_OUTPUT_NAME", "是");
        } else {
            permissionBean.set("PERM_OUTPUT_CODE", "0");
            permissionBean.set("PERM_OUTPUT_NAME", "否");
        }
        if (Strings.isNullOrEmpty(outputTemplate)) {
            permissionBean.set("PERM_OUTPUT_TEMPLATE", outputTemplate);
        }
        //todo 设置租户
        permissionBean.set("SY_TENANT_ID", "");
        permissionBean.set("SY_TENANT_NAME", "");
        permissionBean.set("PERM_EXCLUDE_CODE", "0");
        permissionBean.set("PERM_EXCLUDE_NAME", "否");
        permissionBean.set("PERM_TYPE_CODE", typeEnum.name());
        permissionBean.set("PERM_TYPE_NAME", typeEnum.getDesc());
        permissionBean.set("PERM_OBJECT", object);
        permissionBean.set("PERM_OPERATE_CODE", operationType.getCode());
        permissionBean.set("PERM_OPERATE_NAME", operationType.getDesc());
        metaService.insert(permissionBean);
        return permissionBean;
    }

    public String formatTemplate(String permissionTemplate, Entry... params) {
        EvaluationContext context = new StandardEvaluationContext();
        for (Entry eachEntry : params) {
            context.setVariable(eachEntry.getKey(), eachEntry.getValue());
        }
        return PARSER.parseExpression(permissionTemplate, PARSER_CONTEXT).getValue(context, String.class);
    }

    public static class Entry {

        private String key;
        private Object value;

        public Entry(String key, Object value) {
            this.key = key;
            this.value = value;
        }

        public String getKey() {
            return key;
        }

        public void setKey(String key) {
            this.key = key;
        }

        public Object getValue() {
            return value;
        }

        public void setValue(Object value) {
            this.value = value;
        }

        public static Entry build(String key, Object value) {
            return new Entry(key, value);
        }

    }


}
